﻿-- this file must be encoded by UTF-8 and be run by LuaJIT 2
-- 导出《俺たちに翼はない》的sob文件中字符串的程序 (by dwing)

local ffi = require("ffi")
ffi.cdef[[
int __stdcall MultiByteToWideChar(int cp, int flag, const char* src, int srclen, char* dst, int dstlen);
int __stdcall WideCharToMultiByte(int cp, int flag, const char* src, int srclen, char* dst, int dstlen, const char* defchar, int* used);
]]
local C = ffi.C

local byte = string.byte
local char = string.char
local floor = math.floor
local format = string.format

local fsrc, fdst
local fsrcp = 0

local function Exit()
	if fdst then fdst:close() end
	if fsrc then fsrc:close() end
	os.exit(0)
end

local function Assert(x, ...)
	if x then return x, ... end
	print("ERROR: " .. ...)
	Exit()
end

local function ReadChar()
	local s = fsrc:read(1)
	if not s or #s < 1 then return nil end
	fsrcp = fsrcp + 1
	return byte(s)
end

local function GetJISCharLen(c)
	if not c then return 0 end
	if (c >= 0x81 and c <= 0x9f) or (c >= 0xe0 and c <= 0xfc) then return 2 end
	if (c >= 0x20 and c <= 0x7e) or (c >= 0xa1 and c <= 0xdf) then return 1 end
	if (c == 0x0a or  c == 0x0d) then return 1 end
	return 0
end

local function IsJISSecondChar(c)
	return c >= 0x40 and c <= 0xfc and c ~= 0x7f
end

local function MB_WC(src, cp)
	local srclen = #src
	local dstlen = srclen * 2
	local dst = ffi.new("char[?]", dstlen)
	dstlen = C.MultiByteToWideChar(cp or 0, 0, src, srclen, dst, dstlen) * 2
	return ffi.string(dst, dstlen)
end

local function WC_MB(src, cp)
	local srclen = floor(#src / 2)
	local dstlen = srclen * 3
	local dst = ffi.new("char[?]", dstlen)
	dstlen = C.WideCharToMultiByte(cp or 0, 0, src, srclen, dst, dstlen, nil, nil)
	return ffi.string(dst, dstlen)
end

local function JISToUTF8Str(s)
	return WC_MB(MB_WC(s, 932), 65001)
end

local function Main()
	if not arg[2] then
		print("usage: lua ripsob.lua <input-filename> <output-filename>")
		Exit()
	end

	io.stdout:write(arg[1] .. " => " .. arg[2] .. " ... ")

	fsrc = Assert(io.open(arg[1], "rb"))
	fdst = Assert(io.open(arg[2], "wb"))
	fdst:write("\239\187\191")

	local s = ""
	local haswidechar = false
	local i
	local item = {}

	ReadChar() ReadChar() ReadChar() ReadChar() -- 跳过前4个字符
	while true do
		if #s <= 0 then i = fsrcp end
		local a = ReadChar()
		local len = GetJISCharLen(a)
		if len == 1 then
				if a == 0x0a then s = s .. "\\n"
			elseif a == 0x0d then s = s .. "\\r"
			elseif a == 0x5c then s = s .. "\\\\"
			else s = s .. char(a) end
			if a >= 0x80 then haswidechar = true end
		elseif len == 2 then
			s = s .. char(a)
			a = ReadChar()
			if IsJISSecondChar(a) then
				s = s .. char(a)
				haswidechar = true
			else
				s = ""
				haswidechar = false
			end
		else
			if haswidechar and #s >= 4 then
				item[#item + 1] = format("○%08X○%s\r\n●%08X●%s\r\n\r\n", i, JISToUTF8Str(s), i, JISToUTF8Str(s))
			end
			s = ""
			haswidechar = false
			if not a then break end
		end
	end

--	for i = #item, 1, -1 do
	for i = 1, #item, 1 do
		Assert(fdst:write(item[i]))
	end

	print("OK!")
	Exit()
end

Main()
